<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useVirtualizer } from '@tanstack/vue-virtual'

interface Props {
  items: any[]
  itemWidth?: number
  containerHeight?: number
  containerWidth?: number
  renderAhead?: number
  // 添加滚动到底部的阈值配置
  scrollThreshold?: number
}

const props = withDefaults(defineProps<Props>(), {
  renderAhead: 5,
  itemWidth: 160,
  containerHeight: 200,
  containerWidth: 300,
  scrollThreshold: 100 // 距离底部100px时触发加载
})

const emit = defineEmits<{
  visibleRangeChange: [start: number, end: number]
  // 添加滚动到底部的事件
  reachBottom: []
}>()

const containerRef = ref<HTMLElement>()

// 添加防抖控制
const isLoadingMore = ref(false)
const lastTriggerTime = ref(0)

// 添加触摸事件处理
const handleTouchStart = (e: TouchEvent) => {
  // 阻止事件冒泡，防止影响父级滚动
  e.stopPropagation()
}

const handleTouchMove = (e: TouchEvent) => {
  // 阻止事件冒泡，防止影响父级滚动
  e.stopPropagation()
}

const handleWheel = (e: WheelEvent) => {
  // 如果是水平滚动，阻止垂直滚动传播
  if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) {
    e.stopPropagation()
  }
}

// 使用 @tanstack/vue-virtual - 只支持水平滚动
const virtualizer = useVirtualizer({
  count: props.items.length,
  getScrollElement: () => containerRef.value || null,
  estimateSize: () => props.itemWidth!,
  overscan: props.renderAhead,
  horizontal: true
})

// 添加滚动监听
const handleScroll = () => {
  if (!containerRef.value) return

  const container = containerRef.value
  const scrollLeft = container.scrollLeft
  const scrollWidth = container.scrollWidth
  const clientWidth = container.clientWidth

  // 计算距离右边界的距离
  const distanceToEnd = scrollWidth - scrollLeft - clientWidth

  // 如果距离底部小于阈值，触发加载更多
  if (distanceToEnd <= props.scrollThreshold) {
    const now = Date.now()
    // 防抖：如果正在加载或距离上次触发时间小于1秒，则不触发
    if (now - lastTriggerTime.value > 1000) {
      lastTriggerTime.value = now
      console.log('滚动到底部了')
      emit('reachBottom')
    }
  }

  // 发送可见范围变化事件
  const range = getVisibleRange()
  emit('visibleRangeChange', range.start, range.end)
}

// 滚动到指定位置
const scrollToIndex = (index: number) => {
  virtualizer.value.scrollToIndex(index)
}

// 获取可见范围
const getVisibleRange = () => {
  const range = virtualizer.value.getVirtualItems()
  return {
    start: range[0]?.index || 0,
    end: range[range.length - 1]?.index || 0
  }
}

// 重置加载状态的方法
const resetLoadingState = () => {
  isLoadingMore.value = false
}

defineExpose({
  scrollToIndex,
  getVisibleRange,
  resetLoadingState
})
</script>

<template>
  <div
    ref="containerRef"
    class="virtual-list-container"
    :style="{
      height: `${containerHeight}px`,
      width: `${containerWidth}px`,
      overflow: 'auto'
    }"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @wheel="handleWheel"
    @scroll="handleScroll"
  >
    <div
      :style="{
        height: '100%',
        width: `${virtualizer.getTotalSize()}px`,
        position: 'relative'
      }"
    >
      <div
        v-for="item in virtualizer.getVirtualItems()"
        :key="String(item.key)"
        :style="{
          position: 'absolute',
          top: 0,
          left: 0,
          width: `${item.size}px`,
          height: '100%',
          transform: `translateX(${item.start}px)`
        }"
      >
        <slot
          :item="items[item.index]"
          :index="item.index"
          :style="{
            height: '100%',
            width: `${item.size}px`
          }"
        />
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.virtual-list-container {
  width: 100%;
  position: relative;
  overflow-x: auto;
  overflow-y: hidden;
  white-space: nowrap;

  // 添加更强的滚动隔离
  touch-action: pan-x;
  overscroll-behavior: contain;

  // 横向滑动时，竖向不受影响
  &::-webkit-scrollbar {
    height: 0;
    width: 0;
    background: transparent;
  }

  /* 确保滚动隔离 */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;

  .virtual-list-content {
    width: 100%;
  }
}
</style>
